/**********************************************************************

  Audacity: A Digital Audio Editor

  LV2Effect.cpp

  Audacity(R) is copyright (c) 1999-2008 Audacity Team.
  License: GPL v2 or later.  See License.txt.

**********************************************************************/

#if defined(USE_LV2)

#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wparentheses"
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(__clang__)
#pragma clang diagnostic ignored "-Wparentheses"
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif

#include "LV2Effect.h"
#include "LoadLV2.h"
#include "LV2Instance.h"
#include "LV2Editor.h"
#include "LV2PreferencesDialog.h"
#include "LV2Wrapper.h"

#include <cmath>
#include <exception>
#include <functional>

#ifdef __WXMAC__
#include <wx/evtloop.h>
#endif

#include "AudacityMessageBox.h"

#if defined(__WXGTK__)
#include <gtk/gtk.h>
#endif

#if defined(__WXMSW__)
#include <wx/msw/wrapwin.h>
#endif

LV2Effect::~LV2Effect() = default;

int LV2Effect::ShowClientInterface(const EffectPlugin&, wxWindow& parent,
                                   wxDialog& dialog, EffectEditor* pEditor, bool forceModal) const
{
    if (pEditor) {
        // Remember the dialog with a weak pointer, but don't control its lifetime
        static_cast<LV2Editor*>(pEditor)->mDialog = &dialog;
    }
    // Try to give the window a sensible default/minimum size
    dialog.Layout();
    dialog.Fit();
    dialog.SetMinSize(dialog.GetSize());
    if (mFeatures.mNoResize) {
        dialog.SetMaxSize(dialog.GetSize());
    }
    if ((SupportsRealtime() || GetType() == EffectTypeAnalyze) && !forceModal) {
        dialog.Show();
        return 0;
    }
    return dialog.ShowModal();
}

// May come here before destructive processing
// Or maybe not (if you "Repeat Last Effect")
std::unique_ptr<EffectEditor> LV2Effect::PopulateUI(const EffectPlugin&,
                                                    ShuttleGui& S, EffectInstance& instance, EffectSettingsAccess& access,
                                                    const EffectOutputs* pOutputs) const
{
    auto& settings = access.Get();
    auto parent = S.GetParent();

    auto& myInstance = dynamic_cast<LV2Instance&>(instance);
    auto pWrapper
        =// Output port connection isn't needed for fancy UI wrapper.  Its
         // features are needed to make the suil_instance
          myInstance.MakeWrapper(settings, mProjectRate, nullptr);
    if (!pWrapper) {
        AudacityMessageBox(XO("Couldn't instantiate effect"));
        return nullptr;
    }

    // Determine if the GUI editor is supposed to be used or not
    bool useGUI = false;
    LV2Preferences::GetUseGUI(*this, useGUI);

    // Until I figure out where to put the "Duration" control in the
    // graphical editor, force usage of plain editor.
    if (GetType() == EffectTypeGenerate) {
        useGUI = false;
    }

    auto result = std::make_unique<LV2Editor>(*this, GetType(), mPlug,
                                              dynamic_cast<LV2Instance&>(instance),
                                              access, pOutputs, mProjectRate, mFeatures, mPorts, parent, useGUI);

#ifdef __WXMAC__
    const auto vendor = GetVendor().Msgid().Translation();
    const bool doX42Hack = vendor == "Robin Gareus";
    result->mUI.mJustLeakMemory = doX42Hack;
#endif

    if (result->mUseGUI) {
        result->mUseGUI = result->BuildFancy(move(pWrapper), settings);
    }
    if (!result->mUseGUI && !result->BuildPlain(access)) {
        return nullptr;
    }
    result->UpdateUI();

    return result;
}

std::unique_ptr<EffectEditor> LV2Effect::MakeEditor(
    ShuttleGui&, EffectInstance&, EffectSettingsAccess&,
    const EffectOutputs*) const
{
    //! Will not come here because Effect::PopulateUI is overridden
    assert(false);
    return nullptr;
}

bool LV2Effect::CloseUI() const
{
#ifdef __WXMAC__
#ifdef __WX_EVTLOOP_BUSY_WAITING__
    wxEventLoop::SetBusyWaiting(false);
#endif
#endif

    return true;
}

void LV2Effect::ExportPresets(
    const EffectPlugin&, const EffectSettings&) const
{
}

OptionalMessage LV2Effect::ImportPresets(
    const EffectPlugin&, EffectSettings&) const
{
    return { nullptr };
}

void LV2Effect::ShowOptions(const EffectPlugin&) const
{
    LV2PreferencesDialog { *this }.ShowModal();
}

// Inject factory hook to make LV2Effect capable of UI
static LV2EffectsModule::Factory::SubstituteInUnique<LV2Effect> scope;

#endif
